import os
import sys
import cv2
import torch
import numpy as np
import pandas as pd
from tqdm import tqdm
import albumentations as A
import segmentation_models_pytorch as smp

from torchvision import transforms as T

root_dir = os.path.dirname(os.path.abspath(__file__))
print(root_dir)
sys.path.append(root_dir)
from models import get_model
os.environ["CUDA_VISIBLE_DEVICES"] = "0"
IMAGE_SIZE = 512
DEVICE = 'cuda' if torch.cuda.is_available() else 'cpu' 


trfm = A.Compose([
    A.Resize(IMAGE_SIZE, IMAGE_SIZE),
    A.HorizontalFlip(p=0.5),
    A.VerticalFlip(p=0.5),
    A.RandomRotate90(),
])

as_tensor = T.Compose([
            T.ToTensor(),
            T.Normalize([0.625, 0.448, 0.688],
                        [0.131, 0.177, 0.101]),
        ])


def rle_encode(im):
    '''
    im: numpy array, 1 - mask, 0 - background
    Returns run length as string formated
    '''
    pixels = im.flatten(order = 'F')
    pixels = np.concatenate([[0], pixels, [0]])
    runs = np.where(pixels[1:] != pixels[:-1])[0] + 1
    runs[1::2] -= runs[::2]
    return ' '.join(str(x) for x in runs)

def rle_decode(mask_rle:str, shape=(512, 512)):
    '''
    mask_rle: run-length as string formated (start length)
    shape: (height,width) of array to return 
    Returns numpy array, 1 - mask, 0 - background

    '''
    s = mask_rle.split()
    starts, lengths = [np.asarray(x, dtype=int) for x in (s[0:][::2], s[1:][::2])]
    starts -= 1
    ends = starts + lengths
    img = np.zeros(shape[0]*shape[1], dtype=np.uint8)
    for lo, hi in zip(starts, ends):
        img[lo:hi] = 1
    return img.reshape(shape, order='F')


trfm = T.Compose([
    T.ToPILImage(),
    T.Resize(IMAGE_SIZE),
    T.ToTensor(),
    T.Normalize([0.625, 0.448, 0.688],
                [0.131, 0.177, 0.101]),
])


model = get_model()
model.to(DEVICE)

weight = "fold3_uppmodel_new3.pth"
model.load_state_dict(torch.load(weight))
model.eval()

data_dir = '/dataset/earth_online'
data_path = os.path.join(data_dir, 'test_a_samplesubmit.csv')
test_mask = pd.read_csv(data_path, sep='\t', names=['name', 'mask'])
test_mask['name'] = test_mask['name'].apply(lambda x: os.path.join(data_dir, 'test_a', x))

# print(test_mask['name'][0])
# exit()
# test_mask = pd.read_csv(sub_path, sep='\t', names=['name', 'mask'])
# test_mask['name'] = test_mask['name'].apply(lambda x: './data/test_b/' + x)


subm = []
for idx, name in enumerate(tqdm(test_mask['name'].iloc[:])):
    image = cv2.imread(name)
    image = trfm(image)
    with torch.no_grad():
        image = image.to(DEVICE)[None]
        pred1 = None
        score1 = model(image)[0][0]

        score2 = model(torch.flip(image, [0, 3]))
        score2 = torch.flip(score2, [3, 0])[0][0]

        score3 = model(torch.flip(image, [1, 2]))
        score3 = torch.flip(score3, [2, 1])[0][0]

        score4 = model(torch.flip(image, [0, 2]))
        score4 = torch.flip(score4, [2, 0])[0][0]

        # score_mean = (score1 + score2 + score3 + score4 + score5) / 5.0
        score_mean = (score1 + score2 + score3 + score4) / 4.0

        if pred1 is None:
            pred1 = np.squeeze(score_mean)
        elif pred1 is not None:
            pred1 += np.squeeze(score_mean)

        # number of models
        pred:torch.Tensor = pred1

        score_sigmoid = pred.sigmoid().cpu().numpy()
        score_sigmoid = (score_sigmoid > 0.39).astype(np.uint8)
        score_sigmoid = cv2.resize(score_sigmoid, (512, 512), interpolation = cv2.INTER_CUBIC)
    subm.append([name.split('/')[-1], rle_encode(score_sigmoid)])

subm = pd.DataFrame(subm)
subm.to_csv('./subtt_b_2.csv', index=None, header=None, sep='\t')


